#include "ParkingLot.h"

ParkingLot::ParkingLot() {
	DS::queue<ParkingInfo> q;
	DS::stack<ParkingInfo> s;
	parking_s = s;
	waiting_q = q;
	space_occupied = 0;
	max_car_space = 2;
	park_per_hour = 10;
	wait_per_hour = 1;
	strcpy_s(popInfo,"");
}

ParkingLot::ParkingLot(int max_space) {
	DS::queue<ParkingInfo> q;
	DS::stack<ParkingInfo> s;
	parking_s = s;
	waiting_q = q;
	space_occupied = 0;
	max_car_space = max_space;
	park_per_hour = 10;
	wait_per_hour = 1;
	strcpy_s(popInfo, "");
}

ParkingLot::~ParkingLot() {

}

void ParkingLot::arrive(ParkingInfo const& car) {
	std::string info = "";
	info += "Car ";
	info += car.plateNumber;
	info += " arrives at ";
	info += std::to_string(car.time);

	if (!waiting_q.empty()) {
		waiting_q.push(car);

		info += "\n\nWait in queue.\n\nAt position: ";
		info += std::to_string(waiting_q.size());
		info += "\n\n";
		strcpy_s(popInfo, info.c_str());
	}
	else if ((space_occupied + car.carSize) <= max_car_space) {
		space_occupied += car.carSize;
		parking_s.push(car);

		info += "\n\nPark in the parking lot.\n\nAt position: ";
		info += std::to_string(parking_s.size());
		info += "\n\n";
		strcpy_s(popInfo, info.c_str());
	}
	else {
		waiting_q.push(car);

		info += "\n\nWait in queue.\n\nAt position: ";
		info += std::to_string(waiting_q.size());
		info += "\n\n";
		strcpy_s(popInfo, info.c_str());
	}
}

void ParkingLot::depart(ParkingInfo const& car) {
	std::string info = "";
	info += "Car ";
	info += car.plateNumber;
	info += " departs at ";
	info += std::to_string(car.time);

	for (int i = 0; i < parking_s.size(); i++) {
		if (!strcmp(parking_s.at(i).plateNumber, car.plateNumber)) {
			DS::stack<ParkingInfo> temp_stack;
			for (int j = parking_s.size() - 1; j > i; j--) {
				temp_stack.push(parking_s.top());
				parking_s.pop();
			}

			// Time in queue
			int t1 = parking_s.top().waitingTime;
			// Time in parking lot
			int t2 = car.time - parking_s.top().time - t1;
			// Total charge
			float charge = (t1 * wait_per_hour + t2 * park_per_hour) * parking_s.at(i).carSize;

			info += "\n\nTime in queue: ";
			info += std::to_string(t1);
			info += "\n\nTime in parking lot: ";
			info += std::to_string(t2);
			info += "\n\nTotal charge: $";
			info += std::to_string(charge);
			info += "\n\n";
			strcpy_s(popInfo, info.c_str());

			space_occupied -= parking_s.top().carSize;

			parking_s.pop();

			while (!temp_stack.empty()) {
				parking_s.push(temp_stack.top());
				temp_stack.pop();
			}

			while (!waiting_q.empty()) {
				if (space_occupied + waiting_q.front().carSize <= max_car_space) {
					ParkingInfo tempInfo = waiting_q.front();
					space_occupied += tempInfo.carSize;
					tempInfo.waitingTime = car.time - tempInfo.time;
					parking_s.push(tempInfo);
					waiting_q.pop();
				}
				else break;
			}
			return;
		}
	}

	for (int i = 0; i < waiting_q.size(); i++) {
		if (!strcmp(waiting_q.at(i).plateNumber, car.plateNumber)) {
			float charge = (car.time - waiting_q.at(i).time) * wait_per_hour * waiting_q.at(i).carSize;

			info += "\n\nTime in queue: ";
			info += std::to_string(car.time - waiting_q.at(i).time);
			info += "\n\nTime in parking lot: ";
			info += "0";
			info += "\n\nTotal charge: $";
			info += std::to_string(charge);
			info += "\n\n";
			strcpy_s(popInfo, info.c_str());

			for (int j = 0; j < i; j++) {
				waiting_q.push(waiting_q.front());
				waiting_q.pop();
			}
			waiting_q.pop();
			if (!waiting_q.empty()) {
				while (space_occupied + waiting_q.front().carSize <= max_car_space) {
					ParkingInfo tempInfo = waiting_q.front();
					space_occupied += tempInfo.carSize;
					tempInfo.waitingTime = car.time - tempInfo.time;
					parking_s.push(tempInfo);
					waiting_q.pop();
				}
			}
			return;
		}
	}
	strcpy_s(popInfo, "Car not found!\n\n");
}

void ParkingLot::setParkPerHour(int n) {
	park_per_hour = n;
}

void ParkingLot::setWaitPerHour(int n) {
	wait_per_hour = n;
}

void ParkingLot::setMaxCarSpace(int n) {
	max_car_space = n;
}

int ParkingLot::getParkPerHour() {
	return park_per_hour;
}
int ParkingLot::getWaitPerHour() {
	return wait_per_hour;
}

int ParkingLot::getMaxCarSpace() {
	return max_car_space;
}

int ParkingLot::getStackSize() {
	return parking_s.size();
}

int ParkingLot::getQueueSize() {
	return waiting_q.size();
}

char* ParkingLot::getPlateInStack(int i) {
	return parking_s.at(i).plateNumber;
}
int ParkingLot::getSizeInStack(int i) {
	return parking_s.at(i).carSize;
}
int ParkingLot::getTimeInStack(int i) {
	return parking_s.at(i).time;
}

char* ParkingLot::getPlateInQueue(int i) {
	return waiting_q.at(i).plateNumber;
}
int ParkingLot::getSizeInQueue(int i) {
	return waiting_q.at(i).carSize;
}
int ParkingLot::getTimeInQueue(int i) {
	return waiting_q.at(i).time;
}

char* ParkingLot::getPopInfo() {
	return popInfo;
}